#include "HomeGrid.h"
#include "Units.h"
#include <osg/LineWidth>
#include <osg/Hint>
#include <osg/Image>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <sstream>


const std::string HomeGrid::Name = "__HomeGrid";


HomeGrid::HomeGrid()
{
	m_rGeode = new osg::Geode;
	m_rGeode->setName(Name);
	m_rGeode->setDataVariance(osg::Object::DYNAMIC);
	m_rQuad = createQuad();
	m_rGeode->addDrawable(m_rQuad.get());
}


void HomeGrid::setDimensions(const osg::Vec2s &dimensions)
{
	osg::Vec2 size = osg::Vec2(dimensions.x(), dimensions.y()) * Units::squareSize();
    osg::Vec3 offset = osg::Vec3(0.f, 0.f, 0.f) * Units::squareSize();

	updateQuadDimensions(size, offset);
	offset += osg::Vec3(0, 0, 0.01f);
	updateLines(dimensions, offset);
	m_rGeode->dirtyBound();
}


void HomeGrid::setTexture(const std::string& texturePath)
{
	// Load the texture image.
	// Currently this fails in debug mode due to manifest problems which seem to be rooted in third party libs not being compiled correctly
	osg::ref_ptr<osg::Image> image = osgDB::readImageFile( texturePath );
	// Attach the image in a Texture2D object
	osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
	tex->setImage( image.get() );
	tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
	tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
	m_rQuad->getOrCreateStateSet()->setTextureAttributeAndModes( 0, tex.get(), osg::StateAttribute::ON );
}


void HomeGrid::updateQuadDimensions(const osg::Vec2& size, const osg::Vec3& offset)
{
	// Create an array of four vertices.
	osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
	m_rQuad->setVertexArray( v.get() );
	v->push_back( osg::Vec3( 0.f, 0.f, 0.f ) + offset );
	v->push_back( osg::Vec3( size.x(), 0.f, 0.f ) + offset );
	v->push_back( osg::Vec3( size.x(), size.y(), 0.f ) + offset );
	v->push_back( osg::Vec3( 0.f, size.y(), 0.f ) + offset );

	// Create a Vec2Array of texture coordinates for texture unit 0 and attach it to the geom.
	float w = size.x() / 6.f;
	float d = size.y() / 6.f;
	osg::ref_ptr<osg::Vec2Array> tc = new osg::Vec2Array;
	m_rQuad->setTexCoordArray( 0, tc.get() );
	tc->push_back( osg::Vec2( 0, 0 ) );
	tc->push_back( osg::Vec2( w, 0 ) );
	tc->push_back( osg::Vec2( w, d ) );
	tc->push_back( osg::Vec2( 0, d ) );
}


void HomeGrid::updateLines(const osg::Vec2s& dim, const osg::Vec3& offset)
{
	if(m_rGeode->getNumDrawables() == 2)
	{
		m_rGeode->removeDrawable(m_rLines.get());
	}
	m_rLines = createLines(dim.x(), dim.y(), offset);
	m_rGeode->addDrawable( m_rLines.get() );
}


osg::ref_ptr<osg::Geometry> HomeGrid::createQuad()
{
	// Create an object to store geometry in.
	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

	// Create an array for a single color
	osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
	geom->setColorArray( c.get() );
	geom->setColorBinding( osg::Geometry::BIND_OVERALL );
	c->push_back( osg::Vec4( 1.f, 1.f, 1.f, 1.f ) );

	// Create an array for the single normal.
	osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
	geom->setNormalArray( n.get() );
	geom->setNormalBinding( osg::Geometry::BIND_OVERALL );
	n->push_back( osg::Vec3( 0.f, 0.f, 1.f ) );

	// Draw a four-vertex quad from the stored data.
	geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) );

	return geom;
}

//osg::ref_ptr<osg::Geometry> HomeGrid::createQuad(const osg::Vec2& size, const osg::Vec3& offset, const std::string& texturePath)
//{
//	// Create an object to store geometry in.
//	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
//
//	// Create an array of four vertices.
//	osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
//	geom->setVertexArray( v.get() );
//	v->push_back( osg::Vec3( 0.f, 0.f, 0.f ) + offset );
//	v->push_back( osg::Vec3( size.x(), 0.f, 0.f ) + offset );
//	v->push_back( osg::Vec3( size.x(), size.y(), 0.f ) + offset );
//	v->push_back( osg::Vec3( 0.f, size.y(), 0.f ) + offset );
//
//	// Create an array for a single color
//	osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
//	geom->setColorArray( c.get() );
//	geom->setColorBinding( osg::Geometry::BIND_OVERALL );
//	c->push_back( osg::Vec4( 1.f, 1.f, 1.f, 1.f ) );
//
//	// Create an array for the single normal.
//	osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
//	geom->setNormalArray( n.get() );
//	geom->setNormalBinding( osg::Geometry::BIND_OVERALL );
//	n->push_back( osg::Vec3( 0.f, 0.f, 1.f ) );
//
//	// Draw a four-vertex quad from the stored data.
//	geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) );
//
//	// Create a Vec2Array of texture coordinates for texture unit 0
//	// and attach it to the geom.
//	float w = size.x() / 3.f;
//	float d = size.y() / 3.f;
//	osg::ref_ptr<osg::Vec2Array> tc = new osg::Vec2Array;
//	geom->setTexCoordArray( 0, tc.get() );
//	tc->push_back( osg::Vec2( 0, 0 ) );
//	tc->push_back( osg::Vec2( w, 0 ) );
//	tc->push_back( osg::Vec2( w, d ) );
//	tc->push_back( osg::Vec2( 0, d ) );
//
//	// Load the texture image.
//	// Currently this fails in debug mode due to manifest problems which seem to be rooted in third party libs not being compiled correctly
//	osg::ref_ptr<osg::Image> image = osgDB::readImageFile( texturePath );
//	// Attach the image in a Texture2D object
//	osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
//	tex->setImage( image.get() );
//	tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
//	tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
//	geom->getOrCreateStateSet()->setTextureAttributeAndModes( 0, tex.get(), osg::StateAttribute::ON );
//
//	return geom;
//}


osg::ref_ptr<osg::Geometry> HomeGrid::createLines(int widthCount, int depthCount, const osg::Vec3& offset)
{
	// Create an object to store geometry in.
	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
	
	osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
	geom->setVertexArray( v.get() );
	float w = Units::squareSize() * widthCount;
	float d = Units::squareSize() * depthCount;

	// Create depth lines
	for(float x = 0.f; x < w + 0.1; x += Units::squareSize())
	{
		v->push_back( osg::Vec3( x, 0, 0 ) + offset );
		v->push_back( osg::Vec3( x, d, 0 ) + offset );
	}

	// Create width lines
	for(float y = 0.f; y < d + 0.1; y += Units::squareSize())
	{
		v->push_back( osg::Vec3( 0, y, 0 ) + offset );
		v->push_back( osg::Vec3( w, y, 0 ) + offset );
	}

	// color (black)
	osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
	geom->setColorArray( c.get() );
	geom->setColorBinding( osg::Geometry::BIND_OVERALL );
	c->push_back( osg::Vec4( 0.f, 0.f, 0.f, 1.f ) );

	// Create an array for the single normal.
	osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
	geom->setNormalArray( n.get() );
	geom->setNormalBinding( osg::Geometry::BIND_OVERALL );
	n->push_back( osg::Vec3( 0.f, 0.f, 1.f ) );

	// set states
	geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, 0, v->size() ) );
	geom->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
	geom->getOrCreateStateSet()->setAttributeAndModes( new osg::LineWidth(2.0f) );
	geom->getOrCreateStateSet()->setMode( GL_BLEND, osg::StateAttribute::ON );
	geom->getOrCreateStateSet()->setMode( GL_LINE_SMOOTH, osg::StateAttribute::ON );
	geom->getOrCreateStateSet()->setAttributeAndModes( new osg::Hint(GL_LINE_SMOOTH_HINT, GL_NICEST) );

	return geom;
}
